/*
 * Copyright (C) 2016 Bilibili
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.bilibili.magicasakura.widgets;

import ohos.agp.components.AttrSet;
import ohos.agp.components.ComponentState;
import ohos.agp.components.Text;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.StateElement;
import ohos.agp.render.BlendMode;
import ohos.agp.utils.Color;

import com.bilibili.magicasakura.utils.AttrValue;
import com.bilibili.magicasakura.utils.DrawableUtils;
import com.bilibili.magicasakura.utils.ElementTintUtil;
import com.bilibili.magicasakura.utils.ThemeUtils;
import com.bilibili.magicasakura.utils.TintInfo;
import com.bilibili.magicasakura.utils.TintManager;

/**
 * @author xyczero617@gmail.com
 * @time 15/9/26
 */
public class AppCompatCompoundDrawableHelper extends AppCompatBaseHelper<Text> {

    private TintInfo[] mCompoundDrawableTintInfos = new TintInfo[4];

    private Element[] mCompoundDrawableRes = new Element[4];
    private Color[] mCompoundDrawableTintRes = new Color[4];
    private Color[] mCompoundDrawableTintStateRes = new Color[4];
    private BlendMode[] mCompoundDrawableTintModes = new BlendMode[4];

    AppCompatCompoundDrawableHelper(Text view, TintManager tintManager) {
        super(view, tintManager);
    }

    @SuppressWarnings("ResourceType")
    @Override
    void loadFromAttribute(AttrSet attrs, int defStyleAttr) {
        Element element = null;
        mCompoundDrawableRes[0] = AttrValue.get(attrs, "element_left", element);
        mCompoundDrawableTintRes[0] = AttrValue.get(attrs, "drawableLeftTint", ThemeUtils.themeColor);
        mCompoundDrawableTintStateRes[0] = AttrValue.get(attrs, "drawableLeftStateTint", ThemeUtils.themeColor);
        if (attrs.getAttr("drawableLeftTintMode").isPresent()) {
            mCompoundDrawableTintModes[0] = DrawableUtils.parseTintMode(AttrValue.get(attrs, "drawableLeftTintMode", 0), null);
        }

        mCompoundDrawableRes[1] = AttrValue.get(attrs, "element_top", element);
        mCompoundDrawableTintRes[1] = AttrValue.get(attrs, "drawableTopTint", ThemeUtils.themeColor);
        mCompoundDrawableTintStateRes[1] = AttrValue.get(attrs, "drawableTopStateTint", ThemeUtils.themeColor);
        if (attrs.getAttr("drawableTopTintMode").isPresent()) {
            mCompoundDrawableTintModes[1] = DrawableUtils.parseTintMode(AttrValue.get(attrs, "drawableTopTintMode", 0), null);
        }

        mCompoundDrawableRes[2] = AttrValue.get(attrs, "element_right", element);
        mCompoundDrawableTintRes[2] = AttrValue.get(attrs, "drawableRightTint", ThemeUtils.themeColor);
        mCompoundDrawableTintStateRes[2] = AttrValue.get(attrs, "drawableRightStateTint", ThemeUtils.themeColor);
        if (attrs.getAttr("drawableRightTintMode").isPresent()) {
            mCompoundDrawableTintModes[2] = DrawableUtils.parseTintMode(AttrValue.get(attrs, "drawableRightTintMode", 0), null);
        }

        mCompoundDrawableRes[3] = AttrValue.get(attrs, "element_bottom", element);
        mCompoundDrawableTintRes[3] = AttrValue.get(attrs, "drawableBottomTint", ThemeUtils.themeColor);
        mCompoundDrawableTintStateRes[3] = AttrValue.get(attrs, "drawableBottomStateTint", ThemeUtils.themeColor);
        if (attrs.getAttr("drawableBottomTintMode").isPresent()) {
            mCompoundDrawableTintModes[3] = DrawableUtils.parseTintMode(AttrValue.get(attrs, "drawableBottomTintMode", 0), null);
        }

        setCompoundDrawablesWithIntrinsicBounds(
            getCompoundDrawableByPosition(0),
            getCompoundDrawableByPosition(1),
            getCompoundDrawableByPosition(2),
            getCompoundDrawableByPosition(3));
    }

    /**
     * External use
     */
    public void setCompoundDrawablesWithIntrinsicBounds() {
        if (skipNextApply()) return;
        resetTintResource(null, null, null, null);
        setSkipNextApply(false);
    }

    public void setTintColor(int position, int pressed, int empty) {
        mCompoundDrawableTintRes[position] = new Color(empty);
        mCompoundDrawableTintStateRes[position] = new Color(pressed);
    }

    public void setCompoundDrawablesWithIntrinsicBounds1(Element left, Element top, Element right, Element bottom) {
        resetTintResource(left, top, right, bottom);

        setCompoundDrawablesWithIntrinsicBounds(
            getCompoundDrawableByPosition(0),
            getCompoundDrawableByPosition(1),
            getCompoundDrawableByPosition(2),
            getCompoundDrawableByPosition(3));
    }

    public void setCompoundDrawablesTintList(Color... colors) {
        for (int i = 0; i < colors.length; i++) {
            mCompoundDrawableTintRes[i] = colors[i];
            TintInfo tintInfo = mCompoundDrawableTintInfos[i];
            if (tintInfo != null) {
                tintInfo.mHasTintColor = false;
                tintInfo.mTintColor = 0;
            }
        }
        setCompoundDrawablesWithIntrinsicBounds(
            getCompoundDrawableByPosition(0),
            getCompoundDrawableByPosition(1),
            getCompoundDrawableByPosition(2),
            getCompoundDrawableByPosition(3));
    }

    /**
     * Internal use
     *
     * @param left left
     * @param top top
     * @param right right
     * @param bottom bottom
     */
    private void setCompoundDrawablesWithIntrinsicBounds(Element left, Element top, Element right, Element bottom) {
        if (skipNextApply()) return;
        mView.setAroundElements(left, top, right, bottom);
    }

    private Element getCompoundDrawableByPosition(int i) {
        BlendMode tintMode = mCompoundDrawableTintModes[i];
        Color tintResId = mCompoundDrawableTintRes[i];
        Element resId = mCompoundDrawableRes[i];
        if (tintResId != null) {
            setSupportCompoundDrawableTintModeByPosition(i, tintMode);
            return setSupportCompoundDrawableByPosition(i, tintResId);
        } else {
            return resId;
        }
    }

    private Element setSupportCompoundDrawableByPosition(int position, Color tint) {
        if (tint != null) {
            if (mCompoundDrawableTintInfos[position] == null) {
                mCompoundDrawableTintInfos[position] = new TintInfo();
            }
            mCompoundDrawableTintInfos[position].mHasTintColor = true;
            mCompoundDrawableTintInfos[position].mTintColor = mTintManager.getReplaceColorValue(tint);
        }
        return applySupportCompoundDrawableTint(position);
    }

    private void setSupportCompoundDrawableTintModeByPosition(int position, BlendMode mode) {
        if (mode != null) {
            if (mCompoundDrawableTintInfos[position] == null) {
                mCompoundDrawableTintInfos[position] = new TintInfo();
            }
            mCompoundDrawableTintInfos[position].mHasTintMode = true;
            mCompoundDrawableTintInfos[position].mTintMode = mode;
        }
    }

    private Element applySupportCompoundDrawableTint(int position) {
        Element originDrawable = mView.getAroundElements()[position];
        TintInfo tintInfo = mCompoundDrawableTintInfos[position];
        int themColor = mTintManager.getReplaceColorValue(mCompoundDrawableTintStateRes[position]);
        if (originDrawable != null && tintInfo != null && tintInfo.mHasTintColor) {
            if (originDrawable instanceof StateElement) {
                StateElement compoundDrawable = (StateElement) originDrawable;
                StateElement newElement = new StateElement();
                {
                    //按压状态下的图片
                    int[] pressedStates = {ComponentState.COMPONENT_STATE_PRESSED};
                    int pressedIndex = compoundDrawable.findStateElementIndex(pressedStates);
                    if (pressedIndex >= 0) {
                        Element element = compoundDrawable.getStateElement(pressedIndex);
                        if (element != null) {
                            ElementTintUtil.setColorTint(element, themColor);
                        }
                        newElement.addState(pressedStates, element);
                    }
                }
                {
                    //聚焦状态下的图片
                    int[] focusedStates = {ComponentState.COMPONENT_STATE_FOCUSED};
                    int focusedIndex = compoundDrawable.findStateElementIndex(focusedStates);
                    if (focusedIndex >= 0) {
                        Element element = compoundDrawable.getStateElement(focusedIndex);
                        if (element != null) {
                            ElementTintUtil.setColorTint(element, themColor);
                        }
                        newElement.addState(focusedStates, element);
                    }
                }
                {
                    //正常状态下的图片
                    int[] states = {ComponentState.COMPONENT_STATE_EMPTY};
                    int index = compoundDrawable.findStateElementIndex(states);
                    if (index >= 0) {
                        Element element = compoundDrawable.getStateElement(index);
                        if (element != null) {
                            ElementTintUtil.setColorTint(element, tintInfo.mTintColor);
                        }
                        newElement.addState(states, element);
                    }
                }
                return newElement;
            } else {
                ElementTintUtil.setColorTint(originDrawable, tintInfo.mTintColor);
                return originDrawable;
            }
        }
        return originDrawable;
    }

    private void resetTintResource(Element... resIds) {
        for (int i = 0; i < resIds.length; i++) {
            mCompoundDrawableRes[i] = resIds[i];
            mCompoundDrawableTintRes[i] = null;
            TintInfo tintInfo = mCompoundDrawableTintInfos[i];
            if (tintInfo != null) {
                tintInfo.mHasTintColor = false;
                tintInfo.mTintColor = 0;
                tintInfo.mHasTintMode = false;
                tintInfo.mTintMode = null;
            }
        }
    }

    @Override
    public void tint() {
        setCompoundDrawablesWithIntrinsicBounds(
            getCompoundDrawableByPosition(0),
            getCompoundDrawableByPosition(1),
            getCompoundDrawableByPosition(2),
            getCompoundDrawableByPosition(3));
    }

    public interface CompoundDrawableExtensible {
        void setCompoundDrawableTintList(Color... colors);
    }
}
